#include "graph.h"
#include "utils.h"
#include "set.h"
#include "sortstrategy.h"
#include "bubblesort.h"
#include "mergesort.h"
#include "heapsort.h"
#include "stdsort.h"
#include "algostrategy.h"
#include "kruskals.h"
#include "prims.h"
#include "algo.h"
#include "stdqueue.h"

// So you can see how the points were generated, if you're into that sort of thing
void Graph::generatePoints(const std::string &filename, int size)
{
	std::ofstream fstr(filename.c_str());
	if (!fstr.is_open())
		throw std::runtime_error("Unable to open filename " + filename);

	fstr << size << "\n";

	srand(0);
	for (int i = 0; i < size; i++)
	{
		float x = ((float) rand() / (float) RAND_MAX);
		float y = ((float) rand() / (float) RAND_MAX);

		fstr << x << " " << y << "\n";
	}

	fstr.close();
}

void Graph::savePoints(const std::string &filename)
{
	std::ofstream fstr(filename.c_str());
	if (!fstr.is_open())
		throw std::runtime_error("Unable to open file for saving " + filename);

	fstr << "<svg viewBox='0 0 1 1' width='500' height='500' xmlns='http://www.w3.org/2000/svg'>\n";

	for (int i = 0; i < size; i++)
	{
		fstr << "<circle stroke='black' stroke-width='0.001' r='0.001' ";
		fstr << "cx='" << vertexVector[i].p.x << "' cy='" << vertexVector[i].p.y << "'/>\n";
	}

	fstr << "</svg>\n";

	fstr.close();
}

void Graph::loadPoints(const std::string &filename)
{
	int pos = 0, lineNo = 1;

	beginTimer();

	std::ifstream fstr(filename.c_str());
	if (!fstr.is_open())
		throw std::runtime_error("Unable to open filename " + filename);
		
	std::string line;
	try
	{
		while (getline(fstr, line))
		{
			if (lineNo == 1)
			{
				size = toInt(line);
				//vertexArray = new Vertex[size];
				vertexVector.resize(size);
			}
			else
			{
				// Using the tokenizer here is a bit overkill and not necessary
				std::istringstream iss(line);
				vertexVector[pos++] = Vertex(toFloat(iss), toFloat(iss));
			}

			lineNo++;
		}
	}
	catch (...)
	{
		throw std::runtime_error("Bad file input at line " + lineNo);
	}

#if DEBUG
	std::cerr << size << "\n";
	for (int i = 0; i < size; i++)
		std::cerr << "Vertex: " << vertexVector[i].p.x << ", " << vertexVector[i].p.y << "\n";
#endif

	fstr.close();
	
	endTimer();
	std::cout << "Point loading time: " << getTime() << " s\n";
}

#include <time.h>
void Graph::calculateMST(Algorithm algorithm)
{
	beginTimer();
	switch (algorithm)
	{
		case kruskal_heapsort:			
			{
				Algo algo(new Kruskals);
				algo.compute(vertexVector, edgeList, new HeapSort);			
			}
			break;
			
		case kruskal_mergesort:
			{
				Algo algo(new Kruskals);
				algo.compute(vertexVector, edgeList, new MergeSort);
			}
			break;
			
		case kruskal_bubblesort:
			{
				Algo algo(new Kruskals);
				algo.compute(vertexVector, edgeList, new BubbleSort);	
			}
			break;

		case kruskal_stdsort:
			{
				Algo algo(new Kruskals);
				algo.compute(vertexVector, edgeList, new StdSort);	
			}
			break;
			
		case prim_heap:
			{
				Algo algo(new Prims);
				algo.compute(vertexVector, edgeList, new Heap);
			}		
			break;
			
		case prim_unordered:
			{
				Algo algo(new Prims);
				algo.compute(vertexVector, edgeList, new UnorderedArray);
			}
			break;
		
		case prim_stdqueue:
			{
				Algo algo(new Prims);
				algo.compute(vertexVector, edgeList, new StdQueue);
			}
			break;

		default:
			break;
	}
	endTimer();
	std::cout << "MST computation time: " << getTime() << " s\n";
}

void Graph::saveMST(const std::string &filename)
{
	beginTimer();

	std::ofstream fstr(filename.c_str());
	if (!fstr.is_open())
		throw std::runtime_error("Unable to open file for saving " + filename);

	fstr << "<svg viewBox='0 0 1 1' width='500' height='500' xmlns='http://www.w3.org/2000/svg'>\n";

	Edge *current = edgeList.getNext();

	while (current)
	{
		fstr << "<line stroke='black' stroke-width='0.001' ";
		fstr << "x1='" << vertexVector[current->index1].p.x << "' y1='" << vertexVector[current->index1].p.y << "' ";
		fstr << "x2='" << vertexVector[current->index2].p.x << "' y2='" << vertexVector[current->index2].p.y << "'/>\n";

		current = edgeList.getNext();
	}

	fstr << "</svg>\n";

	fstr.close();
	
	endTimer();
	std::cout << "SVG output time: " << getTime() << " s\n";
}
